#ifndef _LOOPANALYZER_H_
#define _LOOPANALYZER_H_
#include <sstream>
#include <string>
using namespace std;
#include "clang/AST/Decl.h"
#include "clang/AST/DeclGroup.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/TypeLocVisitor.h"
#include "clang/AST/AST.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ParentMap.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/IdentifierTable.h"
// #include "clang/Basic/Diagnostic.h"
#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Index/DeclReferenceMap.h"
#include "clang/Lex/Lexer.h"
#include "clang/Rewrite/ASTConsumers.h"
#include "clang/Rewrite/Rewriter.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/DenseSet.h"

#include "LoopInfo.h"
#include "SubscriptExpr.h"
#include "depSolve.h"

using namespace clang;
using namespace idx;

class LoopAnalyzer: public ASTConsumer,
                  public DeclVisitor<LoopAnalyzer> ,
                  public StmtVisitor<LoopAnalyzer> , 
                  public TypeLocVisitor<LoopAnalyzer> {
    Rewriter Rewrite;
    Diagnostic &Diags;
    const LangOptions &LangOpts;
    unsigned RewriteFailedDiag;
    ASTContext *Context;
    SourceManager *SM;
    TranslationUnitDecl *TUDecl;
    FileID MainFileID;
    const char *MainFileStart, *MainFileEnd;
    // llvm::DenseMap<Stmt *, Stmt *> ReplacedNodes;
    std::string InFileName;
    // llvm::raw_ostream* OutFile; // farmed out to LoopInfo.
    // for Visitors
    Decl *CurrentDecl;

    typedef DeclVisitor<LoopAnalyzer> BaseDeclVisitor;
    typedef StmtVisitor<LoopAnalyzer> BaseStmtVisitor;
    typedef TypeLocVisitor<LoopAnalyzer> BaseTypeLocVisitor;
    using BaseStmtVisitor::Visit; 

public:
    // The LoopNestInfo Object we will populate.
    LoopNestInfo loopInfo;
    
    
    LoopAnalyzer(std::string& inFile, // llvm::raw_ostream *OS,
                 Diagnostic &D, const LangOptions &LOpts);

    virtual ~LoopAnalyzer();

    virtual void Initialize(ASTContext &context);

    // error handling interface
    void reportError(char* msg);
    
    // Process a for loop, solving dependency equations and emitting the comment.
    void processForLoop(ForStmt* fstmt);

    /** Find subexpressions referring to the given array and read their expressions. */
    vector<SubscriptExpr> parseArrayReads(Expr* expr, int stmtIndex); 

    /** Parse an expression representing a single position of a subscript. */
    SubscriptExpr parseSubscriptExpr(Expr* expr, std::string arrayname, int stmtIndex);
  
    // This is called after parsing; it gets the declarations of the TU and VISITs each one.
    void HandleTranslationUnit(ASTContext &C);
  
    string *getCodeString(SourceRange Range);

    //-------------------------------------------------------------
    // It's all boilerplate below here. Please ignore :)
    //-------------------------------------------------------------
    void VisitDeclRefExpr(DeclRefExpr* E);
    
    void Visit(Decl *D);
    
    void VisitDeclaratorDecl(DeclaratorDecl *D);
    
    void VisitFunctionDecl(FunctionDecl *D);
    
    void VisitObjCMethodDecl(ObjCMethodDecl *D);
    
    void VisitBlockDecl(BlockDecl *D);
    
    void VisitVarDecl(VarDecl *D);

    void VisitDecl(Decl *D);

    void VisitDeclContext(DeclContext *DC);

    void VisitDeclStmt(DeclStmt *Node);

    void VisitBlockExpr(BlockExpr *Node);

    void VisitStmt(Stmt *Node);

    void Visit(TypeLoc TL);

    void VisitArrayLoc(ArrayTypeLoc TL);

    void VisitFunctionTypeLoc(FunctionTypeLoc TL);

}; // class LoopAnalyzer

#endif /* _LOOPANALYZER_H_ */
